# __*__ coding:utf-8 __*__
import re
from time import sleep

from selenium.webdriver.common.by import By
from qturboframe.lib.utils.by import By
from qturboframe.lib.utils.CustomError.custom_error import CustomError
from hslib.webdriver.data_change import get_same_value_in_lists, deal_inputdata
from qturboframe.lib.webdriver.remote.webdriver import WebDriver
from qturboframe.lib.webdriver.remote.webelement import WebElement
from qturboframe.lib.webdriver.exceptions import SeleniumError
from qturboframe.lib.ranorex.exceptions import CsClientError
from qturboframe.lib.report.log import logger
from qturboframe.public_ui.base_element import BaseElement
from qturboframe.public_ui.h_ui.checkbox import Checkbox
from qturboframe.public_ui.h_ui.button import Button


class RefactorTable(BaseElement):
    """
    table表格操作

    :Attributes:
     - _driver: 控件所在的当前webdriver对象
     - _element: 控件元素webelement对象
     - timeout: 步骤操作的超时时间

    :Raises:
        当element_para类型错误时则抛出AttributeError异常

    :Example:
     - 例1: Table(webelement)
     - 例2: Table({By.CLASS_NAME:'class_name','text':'文本信息'})
     - 例3: Table({By.CLASS_NAME:'class_name','text':'文本信息'}, father=driver)
     - 例4: Table({By.CLASS_NAME:'class_name','text':'文本信息'}, father=webelement)
    """

    def __init__(self, element_para, father=None, timeout=5, index=1):
        # element_para入参为字符串类型时，默认为查询方式为id
        if isinstance(element_para, dict) and By.TEXT in element_para:
            text = element_para.get(By.TEXT)
            # xpath = ".//table//*[contains(normalize-space(text()),'{}')]//ancestor::div[contains(@class,'h-table-wrapper')][1]".format(text)
            # xpath = ".//table//*[contains(normalize-space(text()),'{}')]//ancestor::table".format(text)
            xpath = ".//table//*[contains(normalize-space(text()),'{}')]//ancestor::div[contains(@class,'h-table-wrapper')]//table".format(
                text)
            element_para = {By.XPATH: xpath}

        if isinstance(element_para, str):
            element_para = {By.ID: element_para}
        if isinstance(element_para, WebElement):
            self._element = element_para
            self._driver = element_para._parent
            self.timeout = timeout
        elif not isinstance(element_para, dict):
            message = 'element_para参数类型不正确！'
            raise SeleniumError(CustomError.Error_EQ03008001_Parameter_InCorrect, message)
        else:
            if father is None:
                message = '未定位元素，father参数不能为None！'
                raise SeleniumError(CustomError.Error_EQ03008001_Parameter_InCorrect, message)
            if isinstance(father, WebDriver):
                self._driver = father
                self.timeout = timeout
            elif isinstance(father, WebElement):
                self._driver = father._parent
                self.timeout = timeout
            else:
                message = 'father参数类型不正确！'
                raise SeleniumError(CustomError.Error_EQ03008001_Parameter_InCorrect, message)

            key_list = [By.ID, By.NAME, By.CLASS_NAME, By.TAG_NAME, By.LINK_TEXT,
                        By.PARTIAL_LINK_TEXT, By.CSS_SELECTOR, By.XPATH]
            element_by = ''
            element_value = ''
            assist = ''
            for key, value in element_para.items():
                if key in key_list:
                    element_by = key
                    element_value = value
                else:
                    assist += '{}:{},'.format(key, value)
            assist = assist.strip(',')
            self._elements = father.find_elements_by_attribute(
                element_by, element_value, assist, self.timeout)

            exception_msg = ""
            for i in range(4):
                try:
                    self._elements = father.find_elements_by_attribute(
                        element_by, element_value, assist, self.timeout)

                    self.header_tables = []
                    self.body_tables = []
                    self.header_fixeds = []
                    self.header_right_fixeds = []
                    self.body_fixeds = []
                    self.body_right_fixeds = []
                    self.fixed_header = None
                    self.fixed_right_header = None
                    self.fixed_body = None
                    self.fixed_right_body = None
                    self.table_body = None
                    self.unfixed_header = None
                    # 获取到头table和身体table
                    for temp in self._elements:
                        # if BaseElement(temp).get_text().strip()!='' and temp.is_displayed():
                        if temp.is_displayed():
                            father_element = temp.find_element_by_attribute("xpath", "..")
                            element_class = father_element.get_attribute("class")
                            if "h-table-header" in element_class:
                                self.header_tables.append(temp)
                            elif "h-table-body" in element_class:
                                self.body_tables.append(temp)
                            elif 'h-simple-content' in element_class:
                                if 'h-table-body' in father_element.find_element_by_attribute('xpath',
                                                                                              "..").get_attribute(
                                    'class'):
                                    self.body_tables.append(temp)
                            elif 'h-table-fixed-header' in element_class:
                                t = father_element.find_element_by_xpath("..")
                                c = t.get_attribute("class")
                                if 'h-table-fixed-right' in c:
                                    self.header_right_fixeds.append(temp)
                                else:
                                    self.header_fixeds.append(temp)
                            elif 'h-table-fixed-body' in element_class:
                                t = father_element.find_element_by_xpath("..")
                                c = t.get_attribute("class")
                                if 'h-table-fixed-right' in c:
                                    self.body_right_fixeds.append(temp)
                                else:
                                    self.body_fixeds.append(temp)
                except Exception as e:
                    sleep(1.0)
                if self.body_tables and len(self.body_tables) > 0:
                    self.table_body = self.body_tables[index - 1]
                if self.table_body:
                    logger.debug("找到了table body")
                    break
                else:
                    logger.debug("没有找到表体，重新查找")
            else:
                logger.debug("当前表格没有数据")
                # 因为有检查table无数据的情况
                self.table_body = None
                # logger.error(exception_msg)
                # raise SeleniumError("表格查找失败!")

            if self.header_tables and len(self.header_tables) > 0:
                self.table_header = self.header_tables[index - 1]
            else:
                if self.body_tables and len(self.body_tables) > 0:
                    self.table_header = self.body_tables[index - 1]

            if self.body_tables and len(self.body_tables) > 0:
                self.table_body = self.body_tables[index - 1]

            if self.header_right_fixeds and len(self.header_right_fixeds) > 0:
                self.fixed_right_header = self.header_right_fixeds[index - 1]

            if self.header_fixeds and len(self.header_fixeds) > 0:
                self.fixed_header = self.header_fixeds[index - 1]

            if self.body_right_fixeds and len(self.body_right_fixeds) > 0:
                self.fixed_right_body = self.body_right_fixeds[index - 1]

            if self.body_fixeds and len(self.body_fixeds) > 0:
                self.fixed_body = self.body_fixeds[index - 1]

            self.__get_pagination()

            self.__go_to_first_page()

            self.table_headers = self.__get_table_no_hidden_titles()

            self.__get_fixed_header_body()

    def select_row(self, header_content: dict, select_all=False):
        '''
        根据列名和列名信息查找BOP的表格中所在的行数,字典key为table为列名，字典值为table为内容

        :Args:
         - header_content: 字典类型，为table的某一header名和某一行的内容组成的字典例如：{'指令序号': '1311', '回溯状态': '正常'}

        :Returns:
            返回查找的某一行所有元素,类型为List<WebElement>

        :Raises:
            SeleniumError: 表格行数查找失败

        :Example:
         - 例: table.get_table_row({'指令序号': '1311', '回溯状态': '正常'})
        '''
        logger.info("选择表格数据开始")
        if not self.table_body:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)
        # 取消所有的选中
        if self.fixed_header:
            locator = "span.h-checkbox"
            span_checkbox = self.fixed_header.exist(By.CSS_SELECTOR, locator)
            if span_checkbox:
                locator = "input[type='checkbox']"
                checkbox = span_checkbox.find_element_by_attribute(By.CSS_SELECTOR, locator)
                if 'h-checkbox-checked' in span_checkbox.get_attribute("class"):
                    self._driver.execute_script("arguments[0].click();", checkbox)
                else:
                    # 先使全选中
                    self._driver.execute_script("arguments[0].click();", checkbox)
                    # 再取消选中
                    self._driver.execute_script("arguments[0].click();", checkbox)

        expected_rows = self._get_expected_rows(header_content, select_all=select_all)

        for row in expected_rows:
            row_index = row[0]
            page_no = row[1]
            logger.info("目标数据在第{}页，第{}行".format(page_no + 1, row_index))
            if self.pagination:
                self.__go_to_target_page(page_no)
                pass
            if self.fixed_body and len(expected_rows) > 1:
                xpath = ".//tr[{}]//input[@type='checkbox']".format(row_index)
                checkbox = self.fixed_body.find_element_by_attribute(By.XPATH, xpath, timeout=1)
                self._driver.execute_script("arguments[0].click();", checkbox)
            elif self.fixed_body and self.fixed_body.get_attribute("innerText").replace("\t", "").replace("\n",
                                                                                                          "") != "":
                xpath = ".//tr[{}]//input[@type='checkbox']".format(row_index)
                checkbox = self.fixed_body.find_element_by_attribute(By.XPATH, xpath, timeout=1)
                self._driver.execute_script("arguments[0].click();", checkbox)
            else:
                xpath = ".//tbody/tr[{}]".format(row_index)
                tr = self.table_body.find_element_by_attribute(By.XPATH, xpath, timeout=1)
                tr.click()
        logger.info("选择表格数据结束")

    def check(self, header_content, expect_data):
        '''
        根据列名和列名信息查找BOP的表格中所在的行数,字典key为table为列名，字典值为table为内容，然后查找expect_data中key指定的列的内容

        :Args:
         - header_content: 字典类型，为table的某一header名和某一行的内容组成的字典例如：{'指令序号': '1311', '回溯状态': '正常'}
         - expect_data: 字典类型

        :Returns:
            返回查找的某一行所有元素,类型为List<WebElement>

        :Raises:
            SeleniumError: 表格行数查找失败

        :Example:
         - 例: table.get_table_row({'指令序号': '1311', '回溯状态': '正常'})
        '''
        logger.info("检查表格数据开始")
        if not self.table_body:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)

        fixed_table_title_list = []
        table_title_list = self.__get_table_titles()  # 得到table的header
        # if self.fixed_header and BaseElement(self.fixed_header).get_text() != '':
        if self.fixed_header and BaseElement(self.fixed_header).element.get_attribute('innerText') != '':
            fixed_table_title_list = self.__get_fixed_table_titles()

        expected_rows = self._get_expected_rows(header_content)
        row_index = expected_rows[0][0]
        page_no = expected_rows[0][1]
        if self.pagination:
            self.__go_to_target_page(page_no)
            pass

        # 检查内容
        fail = False
        for expect_key, expect_value in expect_data.items():

            if expect_key in table_title_list:
                check_index = table_title_list.index(expect_key) + 1
                is_fixed = False
            elif expect_key in fixed_table_title_list:
                check_index = fixed_table_title_list.index(expect_key) + 1
                is_fixed = True
            else:
                raise SeleniumError("没有找到表头:{}".format(fill_key))

            xpath = ".//tr[{}]/td[{}]".format(row_index, check_index)
            cell = None
            if is_fixed:
                cell = self.fixed_body.find_element_by_attribute(By.XPATH, xpath)
            else:
                cell = self.table_body.find_element_by_attribute(By.XPATH, xpath)
            if cell.text.strip() != expect_value.strip():
                fail = True
                logger.error("{}行，‘{}’列中期望的值为：{}".format(row_index, expect_key, expect_value))
                logger.error("{}行，‘{}’列中实际的值为：{}".format(row_index, expect_key, cell.text))
            else:
                logger.info("{}行，‘{}’列中期望的值为：{}".format(row_index, expect_key, expect_value))
                logger.info("{}行，‘{}’列中实际的值为：{}".format(row_index, expect_key, cell.text))

        if fail:
            raise SeleniumError(CustomError.Error_EQ03010003_Verify_Data_InCorrect)
        logger.info("检查表格数据结束")

    def click_cell(self, input_data: dict, click_input: dict, select_all=False):
        '''
        根据列名和列名信息查找BOP的表格中所在的行数,字典key为table为列名，字典值为table为内容，然后点击click_input指定的cell的表格

        :Args:
         - header_content: 字典类型，为table的某一header名和某一行的内容组成的字典例如：{'指令序号': '1311', '回溯状态': '正常'}

        :Returns:
            返回查找的某一行所有元素,类型为List<WebElement>

        :Raises:
            SeleniumError: 表格行数查找失败

        :Example:
         - 例: table.click_cell({'指令序号': '1311', '回溯状态': '正常'},{"操作":"查看用户"})
        '''
        logger.info("点击表格单元格开始")
        if not self.table_body:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)

        expected_rows = self._get_expected_rows(input_data, select_all=select_all)
        row_index = expected_rows[0][0]
        page_no = expected_rows[0][1]
        if self.pagination:
            self.__go_to_target_page(page_no)
            pass

        click_header = None
        click_button_text = None
        for k, v in click_input.items():
            click_header = k
            click_button_text = v

        header_titles = self.__get_table_titles()
        fixed_header_titles = self.__get_fixed_table_titles()
        fixed_right_header_titles = self.__get_fixed_right_table_titles()

        click_header_tag = "fixed_header"
        column_index = -1
        if click_header in header_titles:
            click_header_tag = "header"
            column_index = header_titles.index(click_header) + 1
        elif click_header in fixed_header_titles:
            click_header_tag = "fixed_header"
            column_index = fixed_header_titles.index(click_header) + 1
        elif click_header in fixed_right_header_titles:
            click_header_tag = "fixed_right_header"
            column_index = fixed_right_header_titles.index(click_header) + 1

        if click_header_tag == "fixed_header":
            locator = ".//tr[{}]//td[{}]//ancestor::tr".format(row_index, column_index)
            element = self.fixed_body.find_element_by_attribute(By.XPATH, locator, timeout=self.timeout)
            Button({By.TEXT: click_button_text}, element, timeout=self.timeout).js_click()
            logger.info("点击表格第{}行的“{}”单元格".format(row_index, click_button_text))
        elif click_header_tag == "fixed_right_header":
            locator = ".//tr[{}]//td[{}]//ancestor::tr".format(row_index, column_index)
            element = self.fixed_right_body.find_element_by_attribute(By.XPATH, locator, timeout=self.timeout)
            Button({By.TEXT: click_button_text}, element, timeout=self.timeout).js_click()
            logger.info("点击表格第{}行的“{}”单元格".format(row_index, click_button_text))
        elif click_header_tag == "header":
            locator = ".//tr[{}]//td[{}]//ancestor::tr".format(row_index,
                                                               column_index)
            element = self.table_body.find_element_by_attribute(By.XPATH,
                                                                      locator,
                                                                      timeout=self.timeout)
            Button({By.TEXT: click_button_text}, element,
                   timeout=self.timeout).js_click()
            logger.info(
                "点击表格第{}行的“{}”单元格".format(row_index, click_button_text))
        else:
            message = "没有找到要点击的单元格"
            raise SeleniumError(CustomError.Error_EQ03007011_Table_Cant_Find_Correct_Cell, message)
        logger.info("点击表格单元格结束")

    def auto_fill(self, header_content: dict, input_data: dict):
        '''
        填充指定单元格数据

        :Args:
         - header_content: 字典类型，为table的某一header名和某一行的内容组成的字典例如：{'指令序号': '1311', '回溯状态': '正常'}
         - input_data: 字典类型，输入的数据

        :Returns:
            None

        :Raises:
            SeleniumError: 表格行数查找失败

        :Example:
         - 例: table.auto_fill({'指令序号': '1311', '回溯状态': '正常'},{'指令序号': '1311', '回溯状态': '正常'})
        '''
        if not self.table_body:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)

        logger.info("表单填写开始")
        # header_content = {}
        fill_data = {}
        for key, value in input_data.items():
            if value.endswith("#f"):
                fill_data[key] = value
            else:
                header_content[key] = value

        expected_rows = self._get_expected_rows(header_content, select_all=False)
        row_index = expected_rows[0][0]
        page_no = expected_rows[0][1]
        if self.pagination:
            self.__go_to_target_page(page_no)

        fixed_table_title_list = []
        table_title_list = self.__get_table_titles()  # 得到table的header
        if self.fixed_header and BaseElement(self.fixed_header).element.get_attribute('innerText') != '':
            fixed_table_title_list = self.__get_fixed_table_titles()

        for fill_key, fill_value in fill_data.items():
            fill_index = None
            is_fixed = None
            # 当有fixed body时，要填充的单元格有可能在fixed body中
            if fill_key in table_title_list:
                fill_index = fixed_table_title_list.index(fill_key) + 1
                is_fixed = False
            elif fill_key in fixed_table_title_list:
                fill_index = table_title_list.index(fill_key) + 1
                is_fixed = True
            else:
                message = "没有找到表头:{}".format(fill_key)
                raise SeleniumError(CustomError.Error_EQ03007007_Table_Header_Not_Correct, message)
            locator = ".//tbody/tr[{}]/td[{}]".format(row_index, fill_index)
            if is_fixed:
                cell = self.fixed_body.find_element_by_attribute(By.XPATH, locator)
            else:
                cell = self.table_body.find_element_by_attribute(By.XPATH, locator)

            edit_ele = cell.exist(By.CSS_SELECTOR, ".h-icon-edit", timeout=1)
            if edit_ele:
                edit_ele.click()
                input_ele = cell.find_element_by_attribute(By.CSS_SELECTOR, "input", timeout=1)
                input_ele.send_keys(fill_value)
            else:
                message = "'{}'不是可被填充的单元格".format(edit_ele)
                raise SeleniumError(CustomError.Error_EQ03007010_Table_Cant_Fill, message)
        logger.info("表单填写结束")

    def check_table_row_number(self, expected_row_num):
        """
        校验表格中数据条目数是否符合预期

        Args:
        - expected_row_num: 数据行预期数量

        Returns:
        """
        # if self.table_body == []:
        if not self.table_body:
            actual_row_number = 0
        else:
            trs = self.table_body.find_elements_by_attribute(By.CSS_SELECTOR, "tr")
            actual_row_number = len(trs)
        if int(expected_row_num) != int(actual_row_number):
            err_info = "数据行数量和实际值不一致，期望值为:{},实际值为:{}".format(expected_row_num, actual_row_number)
            raise SeleniumError(CustomError.Error_EQ03010001_Verify_Expect_Actual_Not_Equal, err_info)
        else:
            logger.info("数据行数量符合预期，为:{}".format(actual_row_number))

    def _get_expected_rows(self, header_content, select_all=False):
        self.__go_to_target_page(1)

        expected_rows = []

        query_header_indexes = []
        query_contents = []
        fixed_table_title_list = []
        fixed_right_table_title_list = []
        table_title_list = self.__get_table_titles()  # 得到table的header
        if self.fixed_header and BaseElement(self.fixed_header).element.get_attribute('innerText') != '':
            fixed_table_title_list = self.__get_fixed_table_titles()

        if self.fixed_right_header and BaseElement(self.fixed_right_header).element.get_attribute('innerText') != '':
            fixed_right_table_title_list = self.__get_fixed_right_table_titles()

        for key, value in header_content.items():
            if key in table_title_list:
                query_header_indexes.append((table_title_list.index(key) + 1, ""))  # 得到要查找的header在第几列
                query_contents.append(value)
            elif len(fixed_table_title_list) != 0 and key in fixed_table_title_list:
                query_header_indexes.append((fixed_table_title_list.index(key) + 1, "fixed_table"))  # 得到要查找的header在第几列
                query_contents.append(value)
            elif len(fixed_right_table_title_list) != 0 and key in fixed_right_table_title_list:
                query_header_indexes.append(
                    (fixed_right_table_title_list.index(key) + 1, "fixed_right_table"))  # 得到要查找的header在第几列
                query_contents.append(value)
            else:
                raise SeleniumError("没有找到表头：{}".format(key))

        find = False
        finished = False
        while True:
            # 用多列查找时，查找的第一个内容
            first_query_content = query_contents[0]
            td_xpath = ".//tbody/tr/td[{}]".format(query_header_indexes[0][0])
            tds = []
            if query_header_indexes[0][1] == "fixed_table":
                tds = self.fixed_body.find_elements_by_attribute(By.XPATH, td_xpath, timeout=0.2)
            elif query_header_indexes[0][1] == "fixed_right_table":
                tds = self.fixed_body.find_elements_by_attribute(By.XPATH, td_xpath, timeout=0.2)
            else:
                td_stabily = ".//tbody/tr/td[{}]//*[normalize-space(text())='{}']".format(
                    query_header_indexes[0][0],first_query_content.split(',')[0])
                self.table_body.find_elements_by_attribute(By.XPATH, td_stabily, timeout=4)
                if "已参与" in first_query_content:
                    pass
                tds = self.table_body.find_elements_by_attribute(By.XPATH, td_xpath, timeout=0.2)
            content_list = self.__get_tds_text(tds)
            # 查找的可能是多列数据例如{"指令序号":"51,52"}
            if first_query_content.split(',')[0] in content_list:
                # 先找到和第一个内容匹配的行
                # row_indexes = [index + 1 for index, value in enumerate(content_list) if value == first_query_content]
                row_indexes = [index + 1 for index, value in enumerate(content_list) if
                               value in first_query_content.split(',')]
                for row_index in row_indexes:
                    td = None
                    for index, value in enumerate(query_header_indexes):
                        xpath = ".//tbody/tr[{}]/td[{}]".format(row_index, value[0])
                        td = None
                        if value[1] == "fixed_table":
                            td = self.fixed_body.find_element_by_attribute(By.XPATH, xpath, timeout=1)
                        else:
                            td = self.table_body.find_element_by_attribute(By.XPATH, xpath, timeout=1)
                        # if BaseElement(td).element.get_attribute('innerText').strip() != query_contents[index]:
                        if BaseElement(td).element.get_attribute('innerText').strip() in query_contents[index].split(
                                ','):
                            pass
                        else:
                            break
                    else:
                        find = True
                        finished = True
                        page_no = 0
                        if self.pagination:
                            # 获取到页数
                            page_no = self.__get_current_page()

                        expected_rows.append((row_index, page_no))
                        if select_all:
                            # 找到所有的
                            finished = False
                        else:
                            break

            if finished:
                break

            if not self.pagination:
                # 没有分页标签时
                break

            # 进入下一页
            if not self.__go_to_next_page():
                if not find:
                    message = "在当前页面没有找到此{}内容的行".format(header_content)
                    raise SeleniumError(CustomError.Error_EQ03007003_Not_Find_Correct_Row)
                break

        if not find:
            message = "没有找到符合要求的行:{}".format(header_content)
            raise SeleniumError(CustomError.Error_EQ03007003_Not_Find_Correct_Row)

        return expected_rows

    def __get_fixed_header_body(self):
        '''
        获取冻结列表格头,非冻结列表格头,表格体
        '''
        if not self.table_body:
            return

        locator = ".//ancestor::div[contains(@class,'h-table-wrapper')]//*[contains(@class,'h-table-fixed-header')]//table"
        temps = self.table_body.find_elements_by_attribute(By.XPATH, locator, timeout=0.5)
        for temp in temps:
            if temp.is_displayed():
                self.fixed_header = temp
                break

        locator = ".//ancestor::div[contains(@class,'h-table-wrapper')]//*[contains(@class,'h-table-fixed-body')]//table"
        temps = self.table_body.find_elements_by_attribute(By.XPATH, locator, timeout=0.5)
        for temp in temps:
            if temp.is_displayed():
                self.fixed_body = temp
                break

        locator = ".//ancestor::div[contains(@class,'h-table-wrapper')]//*[contains(@class,'h-table-header')]//table"
        temps = self.table_body.find_elements_by_attribute(By.XPATH, locator, timeout=0.5)
        for temp in temps:
            if temp.is_displayed():
                self.unfixed_header = temp
                break

    def __get_pagination(self):
        locator = ".//ancestor::*[contains(@class,'h-table-box')]//following-sibling::div[contains(@class,'hx-datagrid-pageView')]"
        if self.table_body:
            self.pagination = self.table_body.exist(By.XPATH, locator, timeout=0.1)
        else:
            self.pagination = None

    def __go_to_next_page(self):
        locator = "li[title='下一页']"
        next_page = self.pagination.find_element_by_attribute(By.CSS_SELECTOR, locator, timeout=self.timeout)
        if "h-page-disabled" in next_page.get_attribute("class"):
            # 已经到了最后一页
            return False
        self._driver.execute_script("arguments[0].click();", next_page)
        return True

    def __get_current_page(self):
        if self.pagination:
            locator = "li.h-page-item-active"
            current_page = self.pagination.find_element_by_attribute(By.CSS_SELECTOR, locator, timeout=self.timeout)
            page_no = int(current_page.get_attribute("title"))
            return page_no
        return 0

    def __go_to_target_page(self, page_no):
        if self.pagination:
            if page_no == 0:
                # 没有分页操作的table
                pass
            else:
                if page_no == 1:
                    locator = "ul.h-page li[title='{}']".format(page_no)
                    first_page = self.pagination.find_element_by_attribute(By.CSS_SELECTOR, locator)
                    first_page.click()
                else:
                    # 在分页中有些页面会在....中
                    # 获取到当前所在的页面
                    current_page_no = self.__get_current_page()
                    if page_no > current_page_no:
                        for i in range(page_no - current_page_no):
                            self.__go_to_next_page()
                    elif page_no < current_page_no:
                        for i in range(current_page_no - page_no):
                            self.__go_to_pre_page()
                    else:
                        # 不用跳转页面
                        pass

    def __go_to_first_page(self):
        if self.pagination:
            locator = "li[title='1']"
            first_page = self.pagination.find_element_by_attribute(By.CSS_SELECTOR, locator, timeout=self.timeout)
            self._driver.execute_script("arguments[0].click();", first_page)

    def __get_table_titles(self):
        """
        获取table的header
        """
        # table中有thead标签
        title_td_xpath = ".//thead/tr/th"
        tds = self.table_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
        # 有的table没有thead标签
        if len(tds) == 0:
            title_td_xpath = ".//tr[1]/td"
            tds = self.table_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
        title_list = []
        for td in tds:
            # title_list.append(BaseElement(td).get_text().replace("\n","").replace("\t","").strip())
            title_list.append(
                BaseElement(td).element.get_attribute('innerText').replace("\n", "").replace("\t", "").strip())
        return title_list

    def __get_table_no_hidden_titles(self):
        """
        获取table的header
        """
        if not self.table_body:
            return []

        # table中有thead标签
        title_td_xpath = ".//thead/tr/th[not(contains(@class,'h-table-hidden'))]"
        tds = self.table_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
        # 有的table没有thead标签
        if len(tds) == 0:
            title_td_xpath = ".//tr[1]/td[not(contains(@class,'h-table-hidden'))]"
            tds = self.table_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
        title_list = []
        for td in tds:
            # title_list.append(BaseElement(td).get_text().replace("\n","").replace("\t","").strip())
            title_list.append(
                BaseElement(td).element.get_attribute('innerText').replace("\n", "").replace("\t", "").strip())

        if title_list[-1].strip() == "":
            title_list = title_list[0:-1]
        return title_list

    def __get_fixed_table_titles(self):
        """
        获取table的header
        """
        if self.fixed_header:
            # table中有thead标签
            title_td_xpath = ".//thead/tr/th"
            tds = self.fixed_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
            # 有的table没有thead标签
            if len(tds) == 0:
                title_td_xpath = ".//tr[1]/td"
                tds = self.fixed_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
            title_list = []
            for td in tds:
                title_list.append(
                    BaseElement(td).element.get_attribute('innerText').replace("\n", "").replace("\t", "").strip())
            return title_list
        return []

    def __get_fixed_right_table_titles(self):
        """
        获取table的header
        """
        if self.fixed_right_header:
            # table中有thead标签
            title_td_xpath = ".//thead/tr/th"
            tds = self.fixed_right_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
            # 有的table没有thead标签
            if len(tds) == 0:
                title_td_xpath = ".//tr[1]/td"
                tds = self.fixed_right_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
            title_list = []
            for td in tds:
                title_list.append(
                    BaseElement(td).element.get_attribute('innerText').replace("\n", "").replace("\t", "").strip())
            return title_list
        return []

    # def __get_fixed_table_titles(self):
    #     """
    #     获取table的header
    #     """
    #     #table中有thead标签
    #     title_td_xpath = ".//thead/tr/th"
    #     tds = self.fixed_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
    #     # 有的table没有thead标签
    #     if len(tds)==0:
    #         title_td_xpath = ".//tr[1]/td"
    #         tds = self.fixed_header.find_elements_by_attribute(By.XPATH, title_td_xpath, timeout=0.1)
    #     title_list = []
    #     for td in tds:
    #         # title_list.append(BaseElement(td).get_text().replace("\n","").replace("\t","").strip())
    #         title_list.append(
    #             BaseElement(td).element.get_attribute('innerText').replace("\n", "").replace("\t", "").strip())
    #     return title_list

    def __get_tds_text(self, tds):
        text_list = []
        for td in tds:
            # text_list.append(BaseElement(td).get_text())
            text_list.append(BaseElement(td).element.get_attribute('innerText'))
        return text_list

    def check_tablefull_data(self, check_type, expected_data, tablename="table"):
        # self.all_header_cell_info = {}#字典的键值为列名{text:[text, width, left, colindex, rowindex]}
        # self.all_header_cell_info_colindex = {}#字典的键值为列号 {colindex:[text, width, left, colindex, rowindex]}
        # self.colindex_list = [] #存储字典的键值

        if check_type.lower().strip() == "tablecheck_full":
            # 查找到期望数据中比实际表头多的数据
            need_check_headers = [e for e in expected_data if e not in self.table_headers]
            if len(need_check_headers) != 0:
                message = "tablecheck_full,但是输入的表头信息和实际的表头信息不符=>"+"请确认这些表头信息是否正确：{}, 这些表头信息在当前表格{}中不存在".format(need_check_headers, tablename)
                raise SeleniumError(CustomError.Error_EQ03007006_Table_Data_Not_Correct, message)

            # 查找出期望数据比实际表头少的数据
            need_check_headers = [e for e in self.table_headers if e not in expected_data]
            if len(need_check_headers) != 0:
                message = "tablecheck_full,但是输入的表头信息和实际的表头信息不符=>" + "请确认这些表头信息是否正确：{}，期望数据中没有这些表头的相关信息".format(need_check_headers)
                raise SeleniumError(CustomError.Error_EQ03007006_Table_Data_Not_Correct, message)

    def check_table_data_full(self, header_content=[], expected_data_list=[], check_type="", need_query=False,
                              tablename="table"):
        '''
        检查表格中的数据

        :Args:
         - header_content: 字典类型，为table的某一header名和某一行的内容组成的字典例如：{'指令序号': '1311', '回溯状态': '正常'}，当need_query为False时此值为空
         - expected_data_list: 期待的结果，数据格式为 [{"指令批号": "332", "指令序号": "nocheck", "指令完成情况": "已分发"}
                                                    ,{"指令批号": "331", "指令序号": "331", "指令完成情况": "已分发"}]
         - check_type: 为tablecheck_full和其他，当是tablecheck_full时，则检查表格整行数据
         - need_query：是否需要根据header_content的内容去先查询到目标行，当数据较多时，建议使用页面具有的搜索功能，先搜索出要查找的数据，这样可以提高检查效率

        :Returns:
            None

        :Raises:
            SeleniumError: 表格行数查找失败

        :Example:
         - 例: table.check({'指令序号': '1311', '回溯状态': '正常'},{'指令序号1': '13111', '回溯状态1': '正常1'})
        '''
        if not self.table_body:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)

        if not expected_data_list:
            message = "请检查期望（expected_data_list）数据，此数据为空"
            raise SeleniumError(CustomError.Error_EQ03008002_Parameter_Content_InCorrect, message)

        e_error = ""
        for i in range(3):
            try:
                if need_query:
                    logger.info("获取{}所在行 - 开始".format(header_content))
                    expected_rows = self._get_expected_rows(header_content, select_all=True)
                    logger.info("获取{}所在行 - 结束".format(header_content))
                    logger.info("期望的数据在：{}".format(expected_rows))

                    # 检查数据格式
                    self.check_tablefull_data(check_type, expected_data_list[0], tablename=tablename)

                    logger.info("获取到检查的数据行整行数据 - 开始")
                    # actual_data_list = self.get_table_content(expected_rows, expected_rowindex_info)  # {2: ['指令批号', 90, 0, 2, 1, '332']}
                    actual_data_list, rowindex_list = self.get_table_content(
                        expected_rows)  # {2: ['指令批号', 90, 0, 2, 1, '332']}
                    logger.info("获取到检查的数据行整行数据 - 结束")
                    print("获取实际数据为:", actual_data_list)

                    logger.info("比较数据 - 开始")
                    self._check_full_data(expected_data_list, actual_data_list, rowindex_list, tablename=tablename)
                    logger.info("比较数据 - 结束")
                else:
                    # logger.info("获取表头和表体内容 - 开始")
                    # logger.info("获取表头和表体内容 - 结束")
                    logger.info("获取的表头数据为：{}".format(self.table_headers))
                    all_row_info, row_index_list = self.get_table_all_content(row_number=len(expected_data_list))
                    logger.info("获取的表体数据为：{}".format(all_row_info))

                    logger.info("检查数据格式开始 - 开始")
                    # 检查数据格式
                    self.check_tablefull_data(check_type, expected_data_list[0], tablename=tablename)
                    logger.info("检查数据格式结束 - 开始")

                    logger.info("比较数据 - 开始")
                    self._check_full_data(expected_data_list, all_row_info, row_index_list, tablename=tablename)
                    logger.info("比较数据 - 结束")
                break
            except Exception as e:
                if "Message: stale element reference: element is not attached to the page document" in str(e) \
                        or "元素刷新超时！" in str(e):
                    self.__scroll_horizontal_scoller(0)
                    self.__scroll_height_scoller(0)
                    sleep(1)
                    import traceback
                    logger.debug(str(e))
                    logger.debug(traceback.format_exc())
                    logger.debug("重新获取table信息")
                    self._init_ag_table(self.locator_by, self.locator, index=self.index)
                    e_error = e
                else:
                    import traceback
                    exception_message = e
                    if traceback.print_exc():
                        exception_message = exception_message + str(traceback.print_exc())
                    raise SeleniumError(exception_message)
        else:
            if "Message: stale element reference: element is not attached to the page document" in e_error:
                raise SeleniumError(CustomError.Error_EQ03001003_Not_On_Page, e_error)
            else:
                raise SeleniumError(e_error)

    def get_table_all_content(self, row_number=1, sleep_time=1):
        '''
        获取表体内容

        :Example:
         - 例: ag_table.get_table_all_content()
        '''
        logger.debug("get_table_all_content--开始")
        if not self.table_body:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)

        all_row_info = []  # 二维数组，保存表格中的数据
        row_index_list = []

        locator = ".//tbody/tr"
        rows = self.table_body.find_elements_by_attribute(By.XPATH, locator)
        if len(rows) == 0:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)

        if len(rows) != row_number:
            raise CsClientError("请检查数据，期望检查{}行数据，但是表格中只有数据{}行".format(row_number, len(rows)))

        logger.debug("获取表体内容-开始")
        ex_msg = ""
        for i in range(row_number):
            for ex_i in range(3):
                try:
                    locator = ".//tbody/tr[{}]/td[not(contains(@class,'h-table-hidden'))]".format(i + 1)
                    row_cells = self.table_body.find_elements_by_attribute(By.XPATH, locator)
                    row_text_list = self.__get_tds_text(row_cells)
                    logger.debug("{}行的数据为:{}".format(i + 1, row_text_list))
                    all_row_info.append(row_text_list)
                    row_index_list.append(i + 1)
                    break
                except Exception as e:
                    if "Message: stale element reference: element is not attached to the page document" in str(e):
                        sleep(1)
                        ex_msg = e
                    else:
                        raise CsClientError(e)
            else:
                raise CsClientError(ex_msg)
        logger.debug("获取表体内容-结束")
        return all_row_info, row_index_list

    # def get_table_content(self, expected_rowindex_list, expected_rowindex_info):
    def get_table_content(self, expected_rowindex_list):
        '''
        获取到表体的内容

        :Example:
         - 例: ag_table.get_table_content()
        '''
        # self.__scroll_horizontal_scoller(0)
        # expected_rowindex_list.sort()
        if not self.table_body:
            raise CsClientError(CustomError.Error_EQ03007005_Table_No_Data_In_Table)

        all_row_info = []
        rowindex_list = []
        while True:
            for rowindex in expected_rowindex_list:
                # y = int(expected_rowindex_info[rowindex][0])
                # height = int(expected_rowindex_info[rowindex][1])
                #
                # if y + height < self.__get_scroll_height_top():
                #     self.__scroll_height_scoller(y + height)

                locator = ".//tbody/tr[{}]/td[not(contains(@class,'h-table-hidden'))]".format(rowindex[0])
                row_cells = self.table_body.find_elements_by_attribute(By.XPATH, locator)
                if not row_cells:
                    message = "获取locator为：{}的元素失败".format(locator)
                    raise CsClientError(CustomError.Error_EQ03001000_Cannot_Find_Element)
                row_text_list = self.__get_tds_text(row_cells)
                logger.debug("{}行的数据为:{}".format(rowindex[0], row_text_list))

                row_text_list = self.__get_tds_text(row_cells)

                all_row_info.append(row_text_list)
                rowindex_list.append(rowindex[0])
                # row_cell_info, max_colindex, max_colindex_header,colindex_list, cell_text_info = self.__get_cells_info(cells, rowindex, type="row")
                # if len(all_row_info) - 1 <= i:
                #     # 第一遍时all_row_info是空的数组
                #     all_row_info.append({})
                # pre_value = all_row_info[i]
                # pre_value.update(row_cell_info)
                # all_row_info[i] = pre_value
                # i = i + 1

            # # 下面是为了滚动表格并且判断是否需要继续滚动
            # # 获取到当前页面显示的最右边的列
            # cell = row_cell_info[max_colindex]
            # left = int(cell[1])
            # width = int(cell[2])
            # if left + width < self.container_width:
            #     self.__scroll_horizontal_scoller(left + width)
            # else:
            #     break
            else:
                break

        return all_row_info, rowindex_list

    def _check_full_data(self, expected_data_list, actual_data_list, row_index_list, tablename="table"):
        '''
        实际结果与期望结果的比较
        expected_data_list的数据格式为：[{'指令批号': '332', '指令序号': '331'},{'指令批号': '331', '指令序号': '331'}]
        actual_data_list的数据格式为：[{'指令批号': '332', '指令序号': '331'},{'指令批号': '331', '指令序号': '331'}]
        '''
        error_header = []
        error_list = []
        error = False
        i = 0
        for expected_data in expected_data_list:
            for key, expected_value in expected_data.items():
                if expected_value.lower().strip() == "nocheck":
                    # 不需要检查
                    continue

                actual_data_index = self.table_headers.index(key)
                actual_value = actual_data_list[i][actual_data_index]
                if actual_value:
                    actual_value = actual_value.strip()
                    # 负数需要去掉“-”进行判断
                    if actual_value.replace(',', '').replace(".", "").strip('-').isdigit():
                        actual_value = actual_value.replace(',', '')
                row_index = row_index_list[i]

                if actual_value.strip() == expected_value.strip():
                    logger.info("检查表格‘{}’中第{}行- 表头为“{}”的数据 -- 实际数据为:{},期望数据为：{}".format(tablename, row_index,
                                                                                        key,
                                                                                        actual_value,
                                                                                        expected_value))
                else:
                    logger.error("检查表格‘{}’中第{}行- 表头为“{}”的数据 -- 实际数据为:{},期望数据为：{}".format(tablename, row_index,
                                                                                         key,
                                                                                         actual_value,
                                                                                         expected_value))
                    error = True
                    error_list.append(key)
            i = i + 1
        if len(error_header) != 0:
            message = "请确认表头信息：‘{}’是否正确".format(error_header)
            raise SeleniumError(CustomError.Error_EQ03007007_Table_Header_Not_Correct, message)

        if error:
            message="数据检查，数据校验失败：{}".format(error_list)
            raise SeleniumError(CustomError.Error_EQ03010003_Verify_Data_InCorrect)
